﻿using System;
using System.IO;
using System.Diagnostics;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reflection;
using System.Runtime;
using System.Runtime.Serialization;
using System.Linq;
using System.Text;

namespace PickGold.Collections
{
	/// <summary>
	/// 提供用于在处理 Web 请求时编码和解码 URL 的方法类。
	/// </summary>
	[Serializable]
	public class HttpValueCollection : NameValueCollection
	{
		#region inner class

		private class UrlDecoder
		{
			private int _BufferSize;
			private byte[] _ByteBuffer;
			private char[] _CharBuffer;
			private Encoding _Encoding;
			private int _ByteCount;
			private int _CharCount;

			internal UrlDecoder(int bufferSize, Encoding encoding)
			{
				this._BufferSize = bufferSize;
				this._Encoding = encoding;
				this._CharBuffer = new char[bufferSize];
			}

			internal void AddByte(byte b)
			{
				if (this._ByteBuffer == null)
				{
					this._ByteBuffer = new byte[this._BufferSize];
				}
				this._ByteBuffer[this._ByteCount++] = b;
			}

			internal void AddChar(char ch)
			{
				if (this._ByteCount > 0)
				{
					this.FlushBytes();
				}
				this._CharBuffer[this._CharCount++] = ch;
			}

			private void FlushBytes()
			{
				if (this._ByteCount > 0)
				{
					this._CharCount += this._Encoding.GetChars(this._ByteBuffer, 0, this._ByteCount, this._CharBuffer, this._CharCount);
					this._ByteCount = 0;
				}
			}

			internal string GetString()
			{
				if (this._ByteCount > 0)
				{
					this.FlushBytes();
				}
				if (this._CharCount > 0)
				{
					return new string(this._CharBuffer, 0, this._CharCount);
				}
				return string.Empty;
			}
		}

		private class HtmlEntities
		{
			private static string[] _EntitiesList = new string[] { 
            "\"-quot", "&-amp", "<-lt", ">-gt", "\x00a0-nbsp", "\x00a1-iexcl", "\x00a2-cent", "\x00a3-pound", "\x00a4-curren", "\x00a5-yen", "\x00a6-brvbar", "\x00a7-sect", "\x00a8-uml", "\x00a9-copy", "\x00aa-ordf", "\x00ab-laquo", 
            "\x00ac-not", "\x00ad-shy", "\x00ae-reg", "\x00af-macr", "\x00b0-deg", "\x00b1-plusmn", "\x00b2-sup2", "\x00b3-sup3", "\x00b4-acute", "\x00b5-micro", "\x00b6-para", "\x00b7-middot", "\x00b8-cedil", "\x00b9-sup1", "\x00ba-ordm", "\x00bb-raquo", 
            "\x00bc-frac14", "\x00bd-frac12", "\x00be-frac34", "\x00bf-iquest", "\x00c0-Agrave", "\x00c1-Aacute", "\x00c2-Acirc", "\x00c3-Atilde", "\x00c4-Auml", "\x00c5-Aring", "\x00c6-AElig", "\x00c7-Ccedil", "\x00c8-Egrave", "\x00c9-Eacute", "\x00ca-Ecirc", "\x00cb-Euml", 
            "\x00cc-Igrave", "\x00cd-Iacute", "\x00ce-Icirc", "\x00cf-Iuml", "\x00d0-ETH", "\x00d1-Ntilde", "\x00d2-Ograve", "\x00d3-Oacute", "\x00d4-Ocirc", "\x00d5-Otilde", "\x00d6-Ouml", "\x00d7-times", "\x00d8-Oslash", "\x00d9-Ugrave", "\x00da-Uacute", "\x00db-Ucirc", 
            "\x00dc-Uuml", "\x00dd-Yacute", "\x00de-THORN", "\x00df-szlig", "\x00e0-agrave", "\x00e1-aacute", "\x00e2-acirc", "\x00e3-atilde", "\x00e4-auml", "\x00e5-aring", "\x00e6-aelig", "\x00e7-ccedil", "\x00e8-egrave", "\x00e9-eacute", "\x00ea-ecirc", "\x00eb-euml", 
            "\x00ec-igrave", "\x00ed-iacute", "\x00ee-icirc", "\x00ef-iuml", "\x00f0-eth", "\x00f1-ntilde", "\x00f2-ograve", "\x00f3-oacute", "\x00f4-ocirc", "\x00f5-otilde", "\x00f6-ouml", "\x00f7-divide", "\x00f8-oslash", "\x00f9-ugrave", "\x00fa-uacute", "\x00fb-ucirc", 
            "\x00fc-uuml", "\x00fd-yacute", "\x00fe-thorn", "\x00ff-yuml", "Œ-OElig", "œ-oelig", "Š-Scaron", "š-scaron", "Ÿ-Yuml", "ƒ-fnof", "ˆ-circ", "˜-tilde", "Α-Alpha", "Β-Beta", "Γ-Gamma", "Δ-Delta", 
            "Ε-Epsilon", "Ζ-Zeta", "Η-Eta", "Θ-Theta", "Ι-Iota", "Κ-Kappa", "Λ-Lambda", "Μ-Mu", "Ν-Nu", "Ξ-Xi", "Ο-Omicron", "Π-Pi", "Ρ-Rho", "Σ-Sigma", "Τ-Tau", "Υ-Upsilon", 
            "Φ-Phi", "Χ-Chi", "Ψ-Psi", "Ω-Omega", "α-alpha", "β-beta", "γ-gamma", "δ-delta", "ε-epsilon", "ζ-zeta", "η-eta", "θ-theta", "ι-iota", "κ-kappa", "λ-lambda", "μ-mu", 
            "ν-nu", "ξ-xi", "ο-omicron", "π-pi", "ρ-rho", "ς-sigmaf", "σ-sigma", "τ-tau", "υ-upsilon", "φ-phi", "χ-chi", "ψ-psi", "ω-omega", "ϑ-thetasym", "ϒ-upsih", "ϖ-piv", 
            " -ensp", " -emsp", " -thinsp", "‌-zwnj", "‍-zwj", "‎-lrm", "‏-rlm", "–-ndash", "—-mdash", "‘-lsquo", "’-rsquo", "‚-sbquo", "“-ldquo", "”-rdquo", "„-bdquo", "†-dagger", 
            "‡-Dagger", "•-bull", "…-hellip", "‰-permil", "′-prime", "″-Prime", "‹-lsaquo", "›-rsaquo", "‾-oline", "⁄-frasl", "€-euro", "ℑ-image", "℘-weierp", "ℜ-real", "™-trade", "ℵ-alefsym", 
            "←-larr", "↑-uarr", "→-rarr", "↓-darr", "↔-harr", "↵-crarr", "⇐-lArr", "⇑-uArr", "⇒-rArr", "⇓-dArr", "⇔-hArr", "∀-forall", "∂-part", "∃-exist", "∅-empty", "∇-nabla", 
            "∈-isin", "∉-notin", "∋-ni", "∏-prod", "∑-sum", "−-minus", "∗-lowast", "√-radic", "∝-prop", "∞-infin", "∠-ang", "∧-and", "∨-or", "∩-cap", "∪-cup", "∫-int", 
            "∴-there4", "∼-sim", "≅-cong", "≈-asymp", "≠-ne", "≡-equiv", "≤-le", "≥-ge", "⊂-sub", "⊃-sup", "⊄-nsub", "⊆-sube", "⊇-supe", "⊕-oplus", "⊗-otimes", "⊥-perp", 
            "⋅-sdot", "⌈-lceil", "⌉-rceil", "⌊-lfloor", "⌋-rfloor", "〈-lang", "〉-rang", "◊-loz", "♠-spades", "♣-clubs", "♥-hearts", "♦-diams"
			};
			private static Hashtable _EntitiesLookupTable;
			private static object _LookupLockObject = new object();

			public static char Lookup(string entity)
			{
				if (_EntitiesLookupTable == null)
				{
					lock (_LookupLockObject)
					{
						if (_EntitiesLookupTable == null)
						{
							Hashtable hashtable = new Hashtable();
							foreach (string str in _EntitiesList)
							{
								hashtable[str.Substring(2)] = str[0];
							}
							_EntitiesLookupTable = hashtable;
						}
					}
				}
				var ht = _EntitiesLookupTable[entity];
				if (ht != null)
					return (char)ht;

				return '\0';
			}
		}

		#endregion

		private static char[] _EntityEndingChars = new char[] { ';', '&' };

		/// <summary>
		/// 最大容量
		/// </summary>
		public const int MAX_HTTP_COLLECTION_KEYS = short.MaxValue;//System.Net.Cookie

		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		public HttpValueCollection() : base(StringComparer.OrdinalIgnoreCase) { }
		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		public HttpValueCollection(bool readOnly) : base(StringComparer.OrdinalIgnoreCase) { this.IsReadOnly = readOnly; }
		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		public HttpValueCollection(int capacity) : base(capacity, (IEqualityComparer)StringComparer.OrdinalIgnoreCase) { }
		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		protected HttpValueCollection(SerializationInfo info, StreamingContext context) : base(info, context) { }
		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		public HttpValueCollection(byte[] data, bool readOnly, Encoding encoding) : base(StringComparer.OrdinalIgnoreCase) { this.Init(data, readOnly, encoding); }
		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		public HttpValueCollection(Stream data, bool readOnly, Encoding encoding) : base(StringComparer.OrdinalIgnoreCase) { this.Init(data, readOnly, encoding); }
		/// <summary>
		/// 构造一个 HttpValueCollection 对象
		/// </summary>
		/// <param name="data">分割字符串</param>
		/// <param name="readOnly">是否设置为只读</param>
		/// <param name="urlencoded">是否已编码，如果为True则需要进行URL解码</param>
		/// <param name="encoding">如果需要解码，则此参数为编码字符集</param>
		public HttpValueCollection(string data, bool readOnly, bool urlencoded, Encoding encoding) : base(StringComparer.OrdinalIgnoreCase) { this.Init(data, readOnly, urlencoded, encoding); }
		/// <summary/>
		private void Init(byte[] data, bool readOnly, Encoding encoding)
		{
			if (data != null && data.Length > 0)
				this.FillFromEncodedBytes(data, encoding);
			base.IsReadOnly = readOnly;
		}
		/// <summary/>
		private void Init(Stream data, bool readOnly, Encoding encoding)
		{
			if (data != null && data.Length > 0)
				this.FillFromEncodedBytes(data, encoding);
			base.IsReadOnly = readOnly;
		}
		/// <summary/>
		private void Init(string data, bool readOnly, bool urlencoded, Encoding encoding)
		{
			if (!string.IsNullOrEmpty(data))
				this.FillFromString(data, urlencoded, encoding);
			base.IsReadOnly = readOnly;
		}

		/// <summary>
		/// 将一个 NameObjectCollectionBase 添加到集合。
		/// </summary>
		/// <param name="c">集合</param>
		public void Add(NameObjectCollectionBase c)
		{
			var count = c.Count;
			this.ThrowIfMaxHttpCollectionKeysExceeded(count);
			for (var i = 0; i < count; i++)
			{
				var item = NameObjectCollection.Get(c, i);
				base.Add(NameObjectCollection.GetKey(c, i), NameObjectCollection.Get(c, i) as string);
			}
		}
		/// <summary>
		/// 从字节数组中填充集合
		/// </summary>
		/// <param name="data">字节数组</param>
		/// <param name="encoding">字符集编码</param>
		public void FillFromEncodedBytes(byte[] data, Encoding encoding)
		{
			var l = (data != null) ? data.Length : 0;
			if (encoding == null)
				encoding = Encoding.UTF8;
			for (var i = 0; i < l; i++)
			{
				var n = Reflector.NullString;
				var v = Reflector.NullString;
				this.ThrowIfMaxHttpCollectionKeysExceeded(0);
				var o = i;
				var ii = -1;
				while (i < l)
				{
					var b = data[i];
					if (b == AsciiCode.AMPERSAND)//&
						break;

					if (b == AsciiCode.EQUAL && ii < 0)//=
						ii = i;
					i++;
				}
				if (ii >= 0)
				{
					n = UrlDecode(data, o, ii - o, encoding);
					v = UrlDecode(data, ii + 1, (i - ii) - 1, encoding);
				}
				else
				{
					n = null;
					v = UrlDecode(data, o, i - o, encoding);
				}
				base.Add(n, v);
				if (i == (l - 1) && data[i] == AsciiCode.AMPERSAND)//&
					base.Add(null, string.Empty);
			}
		}
		/// <summary>
		/// 从字节流中填充集合
		/// </summary>
		/// <param name="data">字节数组</param>
		/// <param name="encoding">字符集编码</param>
		public void FillFromEncodedBytes(Stream data, Encoding encoding)
		{
			var L = BitUtil.K;
			var bi = 0;
			var bs = new byte[L];
			var buffer = new byte[L];
			if (encoding == null)
				encoding = Encoding.UTF8;
			var n = Reflector.NullString;
			var v = Reflector.NullString;
			for (; ; )
			{
				var bl = data.Read(buffer, 0, L);
				if (bl == 0)
				{
					if (bi > 0)
						v = UrlDecode(bs, 0, bi, encoding);
					if (n != null || v != null)
					{
						this.ThrowIfMaxHttpCollectionKeysExceeded(0);
						this.Add(n, v);
					}
					n = null;
					v = null;
					break;
				}

				for (var i = 0; i < bl; i++)
				{
					var ii = buffer[i];
					if (ii == AsciiCode.AMPERSAND)//&
					{
						if (bi > 0)
							v = UrlDecode(bs, 0, bi, encoding);
						if (n != null || v != null)
						{
							this.ThrowIfMaxHttpCollectionKeysExceeded(0);
							this.Add(n, v);
						}
						n = null;
						v = null;
						bi = 0;
						continue;
					}

					if (ii == AsciiCode.EQUAL && n == null)//=
					{
						n = UrlDecode(bs, 0, bi, encoding);
						v = null;
						bi = 0;
						continue;
					}

					bs[bi] = (byte)ii;
					bi++;
				}
			}
			bs = null;
			buffer = null;
		}
		/// <summary>
		/// 从分割字符串填充集合
		/// </summary>
		/// <param name="s">分割字符串</param>
		public void FillFromString(string s)
		{
			this.FillFromString(s, false, null);
		}
		/// <summary>
		/// 从分割字符串填充集合
		/// </summary>
		/// <param name="s">分割字符串</param>
		/// <param name="urlencoded">是否已编码，如果为True则需要进行URL解码</param>
		/// <param name="encoding">如果需要解码，则此参数为编码字符集</param>
		public void FillFromString(string s, bool urlencoded, Encoding encoding)
		{
			var l = (s != null) ? s.Length : 0;
			if (encoding == null)
				encoding = Encoding.UTF8;
			for (var i = 0; i < l; i++)
			{
				this.ThrowIfMaxHttpCollectionKeysExceeded(0);
				var ii = i;
				var iii = -1;
				while (i < l)
				{
					var c = s[i];
					if (c == '&')
						break;

					if (c == '=' && iii < 0)
						iii = i;
					i++;
				}
				var n = Reflector.NullString;
				var v = Reflector.NullString;
				if (iii >= 0)
				{
					n = s.Substring(ii, iii - ii);
					v = s.Substring(iii + 1, (i - iii) - 1);
				}
				else
				{
					v = s.Substring(ii, i - ii);
				}
				if (urlencoded)
					base.Add(UrlDecode(n, encoding), UrlDecode(v, encoding));
				else
					base.Add(n, v);
				if (i == (l - 1) && s[i] == '&')
					base.Add(null, string.Empty);
			}
		}
		/// <summary>
		/// 设置为只读
		/// </summary>
		public void MakeReadOnly()
		{
			base.IsReadOnly = true;
		}
		/// <summary>
		/// 设置为可写
		/// </summary>
		public void MakeReadWrite()
		{
			base.IsReadOnly = false;
		}
		/// <summary>
		/// 重置并清空集合
		/// </summary>
		public void Reset()
		{
			base.Clear();
		}
		/// <summary/>
		private void ThrowIfMaxHttpCollectionKeysExceeded(int add)
		{
			if (this.Count + add >= MAX_HTTP_COLLECTION_KEYS)
				throw new InvalidOperationException();
		}

		/// <summary>
		/// 生成与此实例相同的字符串。
		/// </summary>
		/// <returns>其值与此实例相同的字符串。</returns>
		public override string ToString()
		{
			return this.ToString(true);
		}
		/// <summary>
		/// 生成与此实例相同的字符串。
		/// </summary>
		/// <param name="urlencoded">是否要编码，如果为True则表示集合中的键值对未编码，需要编码，否则表示集合中的键值对已编码，无需再次编码。</param>
		/// <returns>其值与此实例相同的字符串。</returns>
		public virtual string ToString(bool urlencoded)
		{
			return this.ToString(urlencoded, null);
		}
		/// <summary>
		/// 生成与此实例相同的字符串。
		/// </summary>
		/// <param name="urlencoded">是否要编码，如果为True则表示集合中的键值对未编码，需要编码，否则表示集合中的键值对已编码，无需再次编码。</param>
		/// <param name="excludeKeys">排除的键名</param>
		/// <returns>其值与此实例相同的字符串。</returns>
		public virtual string ToString(bool urlencoded, IDictionary excludeKeys)
		{
			var c = this.Count;
			if (c == 0)
				return string.Empty;

			var sb = new StringBuilder();
			var f = (excludeKeys != null) && (excludeKeys["__VIEWSTATE"] != null);
			for (var i = 0; i < c; i++)
			{
				var k = this.GetKey(i);
				if (f && k != null && k.StartsWith("__VIEWSTATE", StringComparison.Ordinal))
					continue;

				if (excludeKeys != null && k != null && excludeKeys[k] != null)
					continue;

				var v = Reflector.NullString;
				if (urlencoded)
					k = UrlEncodeUnicode(k);
				var n = !string.IsNullOrEmpty(k) ? (k + "=") : string.Empty;
				var al = (ArrayList)base.BaseGet(i);
				var ii = (al != null) ? al.Count : 0;
				if (sb.Length > 0)
					sb.Append('&');
				if (ii == 1)
				{
					sb.Append(n);
					v = (string)al[0];
					if (urlencoded)
						v = UrlEncodeUnicode(v);
					sb.Append(v);
					continue;
				}

				if (ii == 0)
				{
					sb.Append(n);
					continue;
				}

				for (int j = 0; j < ii; j++)
				{
					if (j > 0)
						sb.Append('&');
					sb.Append(n);
					v = (string)al[j];
					if (urlencoded)
						v = UrlEncodeUnicode(v);
					sb.Append(v);
				}
			}
			return sb.ToString();
		}

		/// <summary>
		/// 生成与此实例相同的字符串。
		/// </summary>
		/// <param name="c">NameValueCollection 对象</param>
		/// <returns>其值与此实例相同的字符串。</returns>
		public static string ToString(NameValueCollection c)
		{
			return HttpValueCollection.ToString(c, true, null);
		}
		/// <summary>
		/// 生成与此实例相同的字符串。
		/// </summary>
		/// <param name="c">NameValueCollection 对象</param>
		/// <param name="urlencoded">是否要编码，如果为True则表示集合中的键值对未编码，需要编码，否则表示集合中的键值对已编码，无需再次编码。</param>
		/// <returns>其值与此实例相同的字符串。</returns>
		public static string ToString(NameValueCollection c, bool urlencoded)
		{
			return HttpValueCollection.ToString(c, urlencoded, null);
		}
		/// <summary>
		/// 生成与此实例相同的字符串。
		/// </summary>
		/// <param name="c">NameValueCollection 对象</param>
		/// <param name="urlencoded">是否要编码，如果为True则表示集合中的键值对未编码，需要编码，否则表示集合中的键值对已编码，无需再次编码。</param>
		/// <param name="excludeKeys">排除的键名</param>
		/// <returns>其值与此实例相同的字符串。</returns>
		public static string ToString(NameValueCollection c, bool urlencoded, IDictionary excludeKeys)
		{
			var l = c.Count;
			if (l == 0)
				return string.Empty;

			var sb = new StringBuilder();
			var f = (excludeKeys != null) && (excludeKeys["__VIEWSTATE"] != null);
			for (var i = 0; i < l; i++)
			{
				var k = c.GetKey(i);
				if (f && k != null && k.StartsWith("__VIEWSTATE", StringComparison.Ordinal))
					continue;

				if (excludeKeys != null && k != null && excludeKeys[k] != null)
					continue;

				var v = Reflector.NullString;
				if (urlencoded)
					k = UrlEncodeUnicode(k);
				var n = !string.IsNullOrEmpty(k) ? (k + "=") : string.Empty;
				var al = c.GetValues(i);
				var ii = (al != null) ? al.Length : 0;
				if (sb.Length > 0)
					sb.Append('&');
				if (ii == 1)
				{
					sb.Append(n);
					v = (string)al[0];
					if (urlencoded)
						v = UrlEncodeUnicode(v);
					sb.Append(v);
					continue;
				}

				if (ii == 0)
				{
					sb.Append(n);
					continue;
				}

				for (var iii = 0; iii < ii; iii++)
				{
					if (iii > 0)
						sb.Append('&');
					sb.Append(n);
					v = (string)al[iii];
					if (urlencoded)
						v = UrlEncodeUnicode(v);
					sb.Append(v);
				}
			}
			return sb.ToString();
		}
		/// <summary/>
		public static string AspCompatUrlEncode(string s)
		{
			s = UrlEncode(s);
			s = s.Replace("!", "%21");
			s = s.Replace("*", "%2A");
			s = s.Replace("(", "%28");
			s = s.Replace(")", "%29");
			s = s.Replace("-", "%2D");
			s = s.Replace(".", "%2E");
			s = s.Replace("_", "%5F");
			s = s.Replace(@"\", "%5C");
			return s;
		}
		/// <summary/>
		public static string CollapsePercentUFromStringInternal(string s, Encoding e)
		{
			var l = s.Length;
			var d = new UrlDecoder(l, e);
			if (s.IndexOf("%u", StringComparison.Ordinal) == -1)
				return s;

			for (var i = 0; i < l; i++)
			{
				var ch = s[i];
				if (((ch == '%') && (i < (l - 5))) && (s[i + 1] == 'u'))
				{
					var i0 = HexToInt(s[i + 2]);
					var i1 = HexToInt(s[i + 3]);
					var i2 = HexToInt(s[i + 4]);
					var i3 = HexToInt(s[i + 5]);
					if (i0 >= 0 && i1 >= 0 && i2 >= 0 && i3 >= 0)
					{
						ch = (char)((i0 << 12) | (i1 << 8) | (i2 << 4) | i3);
						i += 5;
						d.AddChar(ch);
						continue;
					}
				}
				if ((ch & 0xff80) == 0)
					d.AddByte((byte)ch);
				else
					d.AddChar(ch);
			}
			return d.GetString();
		}
		/// <summary/>
		public static string FormatHttpCookieDateTime(DateTime dt)
		{
			if ((dt < DateTime.MaxValue.AddDays(-1.0)) && (dt > DateTime.MinValue.AddDays(1.0)))
				dt = dt.ToUniversalTime();
			return dt.ToString("ddd, dd-MMM-yyyy HH':'mm':'ss 'GMT'", DateTimeFormatInfo.InvariantInfo);
		}
		/// <summary/>
		public static string FormatHttpDateTime(DateTime dt)
		{
			if ((dt < DateTime.MaxValue.AddDays(-1.0)) && (dt > DateTime.MinValue.AddDays(1.0)))
				dt = dt.ToUniversalTime();
			return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
		}
		/// <summary/>
		public static string FormatHttpDateTimeUtc(DateTime dt)
		{
			return dt.ToString("R", DateTimeFormatInfo.InvariantInfo);
		}
		/// <summary/>
		public static string FormatPlainTextAsHtml(string s)
		{
			if (s == null)
				return null;

			var sb = new StringBuilder();
			var sw = new StringWriter(sb);
			FormatPlainTextAsHtml(s, sw);
			return sb.ToString();
		}
		/// <summary/>
		public static void FormatPlainTextAsHtml(string s, TextWriter output)
		{
			if (s == null)
				return;

			var l = s.Length;
			var c = '\0';
			for (var i = 0; i < l; i++)
			{
				var cc = s[i];
				switch (cc)
				{
					case '\n':
						output.Write("<br/>");
						c = cc;
						break;
					case '\r':
						c = cc;
						break;
					case ' ':
						if (c != ' ')
							output.Write(cc);
						else
							output.Write("&nbsp;");
						c = cc;
						break;
					case '"':
						output.Write("&quot;");
						c = cc;
						break;
					case '&':
						output.Write("&amp;");
						c = cc;
						break;
					case '<':
						output.Write("&lt;");
						c = cc;
						break;
					case '>':
						output.Write("&gt;");
						c = cc;
						break;
					default:
						if ((cc >= '\x00a0') && (cc < 'Ā'))
						{
							output.Write("&#");
							output.Write(((int)cc).ToString(NumberFormatInfo.InvariantInfo));
							output.Write(';');
						}
						else
						{
							output.Write(cc);
						}
						c = cc;
						break;
				}
			}
		}
		/// <summary/>
		public static string FormatPlainTextSpacesAsHtml(string s)
		{
			if (s == null)
				return null;

			var sb = new StringBuilder();
			var sw = new StringWriter(sb);
			var l = s.Length;
			for (var i = 0; i < l; i++)
			{
				var c = s[i];
				if (c == ' ')
					sw.Write("&nbsp;");
				else
					sw.Write(c);
			}
			return sb.ToString();
		}
		/// <summary/>
		private static int HexToInt(char h)
		{
			if ((h >= '0') && (h <= '9'))
				return (h - '0');

			if ((h >= 'a') && (h <= 'f'))
				return ((h - 'a') + 10);

			if ((h >= 'A') && (h <= 'F'))
				return ((h - 'A') + 10);

			return -1;
		}

		/// <summary>
		/// 将字符串最小限度地转换为 HTML 编码的字符串。
		/// </summary>
		/// <param name="s">要编码的字符串。</param>
		/// <returns>一个已编码的字符串。</returns>
		public static string HtmlAttributeEncode(string s)
		{
			if (s == null)
				return null;

			var i = IndexOfHtmlAttributeEncodingChars(s, 0);
			if (i == -1)
				return s;

			var sb = new StringBuilder(s.Length + 5);
			var l = s.Length;
			var ii = 0;
			for (; ; )
			{
				if (i > ii)
					sb.Append(s, ii, i - ii);
				switch (s[i])
				{
					case '"':
						sb.Append("&quot;");
						break;
					case '&':
						sb.Append("&amp;");
						break;
					case '<':
						sb.Append("&lt;");
						break;
				}
				ii = i + 1;
				if (ii >= l)
					break;

				i = IndexOfHtmlAttributeEncodingChars(s, ii);
				if (i == -1)
				{
					sb.Append(s, ii, l - ii);
					break;
				}
			}
			return sb.ToString();
		}
		/// <summary>
		/// 将字符串最小限度地转换为 HTML 编码的字符串，并将已编码的字符串发送给 System.IO.TextWriter 输出流。
		/// </summary>
		/// <param name="s">要编码的字符串</param>
		/// <param name="output">System.IO.TextWriter 输出流。</param>
		public static unsafe void HtmlAttributeEncode(string s, TextWriter output)
		{
			if (string.IsNullOrEmpty(s))
				return;

			var i = IndexOfHtmlAttributeEncodingChars(s, 0);
			if (i == -1)
			{
				output.Write(s);
				return;
			}

			var ii = s.Length - i;
			fixed (char* c = s)
			{
				var cc = c;
				while (i-- > 0)
				{
					cc++;
					output.Write(cc[0]);
				}
				while (ii-- > 0)
				{
					cc++;
					var ccc = cc[0];
					if (ccc > '<')
						output.Write(ccc);
					else if (ccc == '"')
						output.Write("&quot;");
					else if (ccc == '&')
						output.Write("&amp;");
					else if (ccc != '<')
						output.Write(ccc);
					else
						output.Write("&lt;");
				}
			}
		}
		/// <summary>
		/// 将已经为 HTTP 传输进行过 HTML 编码的字符串转换为已解码的字符串。
		/// </summary>
		/// <param name="s">要解码的字符串。</param>
		/// <returns>一个已解码的字符串。</returns>
		public static string HtmlDecode(string s)
		{
			if (s == null)
				return null;

			if (s.IndexOf('&') < 0)
				return s;

			var sb = new StringBuilder();
			var sw = new StringWriter(sb);
			HtmlDecode(s, sw);
			return sb.ToString();
		}
		/// <summary>
		/// 将已经过 HTML 编码的字符串转换为已解码的字符串并将其发送给 System.IO.TextWriter 输出流。
		/// </summary>
		/// <param name="s">要解码的字符串。</param>
		/// <param name="output">System.IO.TextWriter 输出流。</param>
		public static void HtmlDecode(string s, TextWriter output)
		{
			if (string.IsNullOrEmpty(s))
				return;

			if (s.IndexOf('&') < 0)
			{
				output.Write(s);
				return;
			}

			var l = s.Length;
			for (var i = 0; i < l; i++)
			{
				var c = s[i];
				if (c != '&')
				{
					output.Write(c);
					continue;
				}

				var ii = s.IndexOfAny(_EntityEndingChars, i + 1);
				if ((ii <= 0) || (s[ii] != ';'))
				{
					output.Write(c);
					continue;
				}

				var t = s.Substring(i + 1, (ii - i) - 1);
				if ((t.Length > 1) && (t[0] == '#'))
				{
					try
					{
						if ((t[1] == 'x') || (t[1] == 'X'))
							c = (char)int.Parse(t.Substring(2), NumberStyles.AllowHexSpecifier);
						else
							c = (char)int.Parse(t.Substring(1));
						i = ii;
					}
					catch (FormatException)
					{
						i++;
					}
					catch (ArgumentException)
					{
						i++;
					}
					output.Write(c);
					continue;
				}

				i = ii;
				c = HtmlEntities.Lookup(t);
				if (c != '\0')
				{
					output.Write(c);
					continue;
				}

				output.Write('&');
				output.Write(t);
				output.Write(';');
			}
		}
		/// <summary>
		/// 将对象的字符串表示形式转换为 HTML 编码的字符串，并返回编码的字符串。
		/// </summary>
		/// <param name="s">一个对象。</param>
		/// <returns>一个已编码的字符串。</returns>
		public static string HtmlEncode(string s)
		{
			if (s == null)
				return null;

			int i = IndexOfHtmlEncodingChars(s, 0);
			if (i == -1)
				return s;

			var sb = new StringBuilder(s.Length + 5);
			var l = s.Length;
			var ii = 0;
			for (; ; )
			{
				if (i > ii)
				{
					sb.Append(s, ii, i - ii);
				}
				var c = s[i];
				if (c > '>')
				{
					sb.Append("&#");
					sb.Append(((int)c).ToString(NumberFormatInfo.InvariantInfo));
					sb.Append(';');
					break;
				}

				switch (c)
				{
					case '"':
						sb.Append("&quot;");
						break;
					case '<':
						sb.Append("&lt;");
						break;
					case '=':
						break;
					case '>':
						sb.Append("&gt;");
						break;
					case '&':
						sb.Append("&amp;");
						break;
				}
				ii = i + 1;
				if (ii >= l)
					break;

				i = IndexOfHtmlEncodingChars(s, ii);
				if (i == -1)
				{
					sb.Append(s, ii, l - ii);
					break;
				}
			}
			return sb.ToString();
		}
		/// <summary>
		/// 将字符串转换为 HTML 编码的字符串并将输出作为 System.IO.TextWriter 输出流返回。
		/// </summary>
		/// <param name="s"> 要编码的字符串</param>
		/// <param name="output">System.IO.TextWriter 输出流。</param>
		public static unsafe void HtmlEncode(string s, TextWriter output)
		{
			if (s == null)
				return;

			var i = IndexOfHtmlEncodingChars(s, 0);
			if (i == -1)
			{
				output.Write(s);
				return;
			}

			var ii = s.Length - i;
			fixed (char* c = s)
			{
				var cc = c;
				while (i-- > 0)//插入无需编码的前部分字符
				{
					cc++;
					output.Write(cc[0]);
				}
				while (ii-- > 0)//插入需要编码的后部分字符
				{
					cc++;
					var c0 = cc[0];
					var c1 = cc[0];
					if (c0 > '>')
					{
						if ((c0 >= '\x00a0') && (c0 < 'Ā'))
						{
							output.Write("&#");
							output.Write(((int)c0).ToString(NumberFormatInfo.InvariantInfo));
							output.Write(';');
						}
						else
						{
							output.Write(c0);
						}
					}
					switch (c1)
					{
						case '"':
							output.Write("&quot;");
							break;
						case '<':
							output.Write("&lt;");
							break;
						case '=':
							output.Write(c0);
							break;
						case '>':
							output.Write("&gt;");
							break;
						case '&':
							output.Write("&amp;");
							break;
						default:
							output.Write(c0);
							break;
					}
				}
			}
		}
		/// <summary/>
		private static unsafe int IndexOfHtmlAttributeEncodingChars(string s, int start)
		{
			var i = s.Length - start;
			fixed (char* c = s)
			{
				var cc = c + start;
				while (i > 0)
				{
					char ch = cc[0];
					if (ch <= '<')
					{
						switch (ch)
						{
							case '"':
							case '&':
							case '<':
								return (s.Length - i);
						}
					}
					cc++;
					i--;
				}
			}
			return -1;
		}
		/// <summary/>
		private static unsafe int IndexOfHtmlEncodingChars(string s, int start)
		{
			var i = s.Length - start;
			fixed (char* c = s)
			{
				var cc = c + start;
				while (i > 0)
				{
					var ch = cc[0];
					if (ch >= '\x00a0' && ch < 'Ā')
						return (s.Length - i);

					if (ch <= '>')
					{
						switch (ch)
						{
							case '<':
							case '>':
							case '"':
							case '&':
								return s.Length - i;
							//case '=':
							//    break;
						}
					}
					cc++;
					i--;
				}
			}
			return -1;
		}
		/// <summary/>
		public static char IntToHex(int n)
		{
			if (n <= 9)
				return (char)(n + 0x30);

			return (char)((n - 10) + 0x61);
		}
		/// <summary/>
		private static bool IsNonAsciiByte(byte b)
		{
			if (b < 0x7f)
				return (b < 0x20);

			return true;
		}
		/// <summary/>
		public static bool IsSafe(char c)
		{
			if (((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) || (c >= '0' && c <= '9'))
				return true;

			switch (c)
			{
				case '\'':
				case '(':
				case ')':
				case '*':
				case '-':
				case '.':
				case '_':
				case '!':
					return true;
			}
			return false;
		}
		/// <summary>
		/// 使用 System.Text.Encoding.UTF8 编码将查询字符串分析成一个 System.Collections.Specialized.NameValueCollection。
		/// </summary>
		/// <param name="query">要分析的查询字符串。</param>
		/// <returns>查询参数和值的 System.Collections.Specialized.NameValueCollection。</returns>
		public static NameValueCollection ParseQueryString(string query)
		{
			if (query == null)
				return null;

			if ((query.Length > 0) && (query[0] == '?'))
				query = query.Substring(1);
			return new HttpValueCollection(query, true, true, null);
		}
		/// <summary>
		/// 使用指定的 System.Text.Encoding 将查询字符串分析成一个 System.Collections.Specialized.NameValueCollection。
		/// </summary>
		/// <param name="query">要分析的查询字符串。</param>
		/// <param name="encoding">要使用的 System.Text.Encoding。</param>
		/// <returns>查询参数和值的 System.Collections.Specialized.NameValueCollection。</returns>
		public static NameValueCollection ParseQueryString(string query, Encoding encoding)
		{
			if (query == null)
				return null;

			if ((query.Length > 0) && (query[0] == '?'))
				query = query.Substring(1);
			return new HttpValueCollection(query, true, true, encoding);
		}
		/// <summary>
		/// 将已经为在 URL 中传输而编码的字符串转换为解码的字符串。
		/// </summary>
		/// <param name="s">要解码的字符串。</param>
		/// <returns>一个已解码的字符串。</returns>
		public static string UrlDecode(string s)
		{
			if (s == null)
				return null;

			return UrlDecode(s, Encoding.UTF8);
		}
		/// <summary>
		/// 使用指定的解码对象将 URL 编码的字节数组转换为已解码的字符串。
		/// </summary>
		/// <param name="bytes">要解码的字节数组。</param>
		/// <param name="e">指定解码方法的 System.Text.Encoding。</param>
		/// <returns>一个已解码的字符串。</returns>
		public static string UrlDecode(byte[] bytes, Encoding e)
		{
			if (bytes == null)
				return null;

			return UrlDecode(bytes, 0, bytes.Length, e);
		}
		/// <summary>
		/// 使用指定的编码对象将 URL 编码的字符串转换为已解码的字符串。
		/// </summary>
		/// <param name="s">要解码的字符串。</param>
		/// <param name="e">指定解码方法的 System.Text.Encoding。</param>
		/// <returns>一个已解码的字符串。</returns>
		public static string UrlDecode(string s, Encoding e)
		{
			if (s == null)
				return null;

			return UrlDecodeStringFromStringInternal(s, e);
		}
		/// <summary>
		/// 使用指定的编码对象，从数组中的指定位置开始到指定的字节数为止，将 URL 编码的字节数组转换为已解码的字符串。
		/// </summary>
		/// <param name="bytes">要解码的字节数组。</param>
		/// <param name="offset">字节中开始解码的位置。</param>
		/// <param name="count">要解码的字节数。</param>
		/// <param name="e">指定解码方法的 System.Text.Encoding 对象。</param>
		/// <returns>一个已解码的字符串。</returns>
		public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
		{
			if ((bytes == null) && (count == 0))
				return null;

			if (bytes == null)
				return null;

			if ((offset < 0) || (offset > bytes.Length))
				throw new ArgumentOutOfRangeException("offset");

			if ((count < 0) || ((offset + count) > bytes.Length))
				throw new ArgumentOutOfRangeException("count");

			return UrlDecodeStringFromBytesInternal(bytes, offset, count, e);
		}
		/// <summary/>
		private static byte[] UrlDecodeBytesFromBytesInternal(byte[] bytes, int offset, int count)
		{
			var l = 0;
			var bs = new byte[count];
			for (var i = 0; i < count; i++)
			{
				var index = offset + i;
				var v = bytes[index];
				if (v == 0x2b)
				{
					v = 0x20;
				}
				else if ((v == 0x25) && (i < (count - 2)))
				{
					int i0 = HexToInt((char)bytes[index + 1]);
					int i1 = HexToInt((char)bytes[index + 2]);
					if ((i0 >= 0) && (i1 >= 0))
					{
						v = (byte)((i0 << 4) | i1);
						i += 2;
					}
				}
				bs[l++] = v;
			}
			if (l < bs.Length)
			{
				var ts = new byte[l];
				Array.Copy(bs, ts, l);
				bs = ts;
			}
			return bs;
		}
		/// <summary/>
		private static string UrlDecodeStringFromBytesInternal(byte[] bytes, int offset, int count, Encoding e)
		{
			var d = new UrlDecoder(count, e);
			for (var i = 0; i < count; i++)
			{
				var ii = offset + i;
				var b = bytes[ii];
				if (b == 0x2B)
				{
					b = 0x20;
				}
				else if ((b == 0x25) && (i < (count - 2)))
				{
					if ((bytes[ii + 1] == 0x75) && (i < (count - 5)))
					{
						var i2 = HexToInt((char)bytes[ii + 2]);
						var i3 = HexToInt((char)bytes[ii + 3]);
						var i4 = HexToInt((char)bytes[ii + 4]);
						var i5 = HexToInt((char)bytes[ii + 5]);
						if (((i2 < 0) || (i3 < 0)) || ((i4 < 0) || (i5 < 0)))
						{
							d.AddByte(b);
							break;
						}

						var ch = (char)((((i2 << 12) | (i3 << 8)) | (i4 << 4)) | i5);
						i += 5;
						d.AddChar(ch);
						continue;
					}

					var i0 = HexToInt((char)bytes[ii + 1]);
					var i1 = HexToInt((char)bytes[ii + 2]);
					if ((i0 >= 0) && (i1 >= 0))
					{
						b = (byte)((i0 << 4) | i1);
						i += 2;
					}
				}
				d.AddByte(b);
			}
			return d.GetString();
		}
		/// <summary/>
		private static string UrlDecodeStringFromStringInternal(string s, Encoding e)
		{
			int length = s.Length;
			var decoder = new UrlDecoder(length, e);
			for (int i = 0; i < length; i++)
			{
				char ch = s[i];
				if (ch == '+')
				{
					ch = ' ';
				}
				else if ((ch == '%') && (i < (length - 2)))
				{
					if ((s[i + 1] == 'u') && (i < (length - 5)))
					{
						int num3 = HexToInt(s[i + 2]);
						int num4 = HexToInt(s[i + 3]);
						int num5 = HexToInt(s[i + 4]);
						int num6 = HexToInt(s[i + 5]);
						if (((num3 < 0) || (num4 < 0)) || ((num5 < 0) || (num6 < 0)))
						{
							goto Label_0106;
						}
						ch = (char)((((num3 << 12) | (num4 << 8)) | (num5 << 4)) | num6);
						i += 5;
						decoder.AddChar(ch);
						continue;
					}
					int num7 = HexToInt(s[i + 1]);
					int num8 = HexToInt(s[i + 2]);
					if ((num7 >= 0) && (num8 >= 0))
					{
						byte b = (byte)((num7 << 4) | num8);
						i += 2;
						decoder.AddByte(b);
						continue;
					}
				}
			Label_0106:
				if ((ch & 0xff80) == 0)
				{
					decoder.AddByte((byte)ch);
				}
				else
				{
					decoder.AddChar(ch);
				}
			}
			return decoder.GetString();
		}
		/// <summary>
		/// 将 URL 编码的字节数组转换为已解码的字节数组。
		/// </summary>
		/// <param name="bytes">要解码的字节数组。</param>
		/// <returns>一个已解码的字节数组。</returns>
		public static byte[] UrlDecodeToBytes(byte[] bytes)
		{
			if (bytes == null)
				return null;

			return UrlDecodeToBytes(bytes, 0, (bytes != null) ? bytes.Length : 0);
		}
		/// <summary>
		/// 将 URL 编码的字符串转换为已解码的字节数组。
		/// </summary>
		/// <param name="s">要解码的字符串。</param>
		/// <returns>一个已解码的字节数组。</returns>
		public static byte[] UrlDecodeToBytes(string s)
		{
			if (s == null)
				return null;

			return UrlDecodeToBytes(s, Encoding.UTF8);
		}
		/// <summary>
		/// 使用指定的解码对象将 URL 编码的字符串转换为已解码的字节数组。
		/// </summary>
		/// <param name="s">要解码的字符串。</param>
		/// <param name="e">指定解码方法的 System.Text.Encoding 对象。</param>
		/// <returns>一个已解码的字节数组。</returns>
		public static byte[] UrlDecodeToBytes(string s, Encoding e)
		{
			if (s == null)
				return null;

			return UrlDecodeToBytes(e.GetBytes(s));
		}
		/// <summary>
		/// 从数组中的指定位置开始一直到指定的字节数为止，将 URL 编码的字节数组转换为已解码的字节数组。
		/// </summary>
		/// <param name="bytes">要解码的字节数组。</param>
		/// <param name="offset">字节数组中开始解码的位置。</param>
		/// <param name="count">要解码的字节数。</param>
		/// <returns>一个已解码的字节数组。</returns>
		public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
		{
			if ((bytes == null) && (count == 0))
				return null;

			if (bytes == null)
				throw new ArgumentNullException("bytes");

			if ((offset < 0) || (offset > bytes.Length))
				throw new ArgumentOutOfRangeException("offset");

			if ((count < 0) || ((offset + count) > bytes.Length))
				throw new ArgumentOutOfRangeException("count");

			return UrlDecodeBytesFromBytesInternal(bytes, offset, count);
		}
		/// <summary>
		/// 将字节数组转换为编码的 URL 字符串。
		/// </summary>
		/// <param name="bytes">要编码的字节数组。</param>
		/// <returns>一个已编码的字符串。</returns>
		public static string UrlEncode(byte[] bytes)
		{
			if (bytes == null)
				return null;

			return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes));
		}
		/// <summary>
		/// 对 URL 字符串进行编码。
		/// </summary>
		/// <param name="s">要编码的文本。</param>
		/// <returns>一个已编码的字符串。</returns>
		public static string UrlEncode(string s)
		{
			if (s == null)
				return null;

			return UrlEncode(s, Encoding.UTF8);
		}
		/// <summary>
		/// 使用指定的编码对象对 URL 字符串进行编码。
		/// </summary>
		/// <param name="s">要编码的文本。</param>
		/// <param name="e">指定编码方案的 System.Text.Encoding 对象。</param>
		/// <returns>一个已编码的字符串。</returns>
		public static string UrlEncode(string s, Encoding e)
		{
			if (s == null)
				return null;

			return Encoding.ASCII.GetString(UrlEncodeToBytes(s, e));
		}
		/// <summary>
		/// 从数组的指定位置开始到指定的字节数为止，将字节数组转换为 URL 编码的字符串。
		/// </summary>
		/// <param name="bytes">要编码的字节数组。</param>
		/// <param name="offset">字节数组中开始编码的位置。</param>
		/// <param name="count">要编码的字节数。</param>
		/// <returns>一个已编码的字符串。</returns>
		public static string UrlEncode(byte[] bytes, int offset, int count)
		{
			if (bytes == null)
				return null;

			return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
		}
		/// <summary/>
		private static byte[] UrlEncodeBytesToBytesInternal(byte[] bytes, int offset, int count, bool alwaysCreateReturnValue)
		{
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < count; i++)
			{
				char ch = (char)bytes[offset + i];
				if (ch == ' ')
				{
					num++;
				}
				else if (!IsSafe(ch))
				{
					num2++;
				}
			}
			if ((!alwaysCreateReturnValue && (num == 0)) && (num2 == 0))
			{
				return bytes;
			}
			byte[] buffer = new byte[count + (num2 * 2)];
			int num4 = 0;
			for (int j = 0; j < count; j++)
			{
				byte num6 = bytes[offset + j];
				char ch2 = (char)num6;
				if (IsSafe(ch2))
				{
					buffer[num4++] = num6;
				}
				else if (ch2 == ' ')
				{
					buffer[num4++] = 0x2b;
				}
				else
				{
					buffer[num4++] = 0x25;
					buffer[num4++] = (byte)IntToHex((num6 >> 4) & 15);
					buffer[num4++] = (byte)IntToHex(num6 & 15);
				}
			}
			return buffer;
		}
		/// <summary/>
		private static byte[] UrlEncodeBytesToBytesInternalNonAscii(byte[] bytes, int offset, int count, bool alwaysCreateReturnValue)
		{
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				if (IsNonAsciiByte(bytes[offset + i]))
				{
					num++;
				}
			}
			if (!alwaysCreateReturnValue && (num == 0))
			{
				return bytes;
			}
			byte[] buffer = new byte[count + (num * 2)];
			int num3 = 0;
			for (int j = 0; j < count; j++)
			{
				byte b = bytes[offset + j];
				if (IsNonAsciiByte(b))
				{
					buffer[num3++] = 0x25;
					buffer[num3++] = (byte)IntToHex((b >> 4) & 15);
					buffer[num3++] = (byte)IntToHex(b & 15);
				}
				else
				{
					buffer[num3++] = b;
				}
			}
			return buffer;
		}
		/// <summary>
		/// 将传入的字符串中的非ASCII字符进行编码。
		/// </summary>
		/// <param name="s">要编码的字节数组。</param>
		/// <param name="e">指定编码方案的 System.Text.Encoding。</param>
		/// <returns>一个已编码的字节数组。</returns>
		public static string UrlEncodeNonAscii(string s, Encoding e)
		{
			if (string.IsNullOrEmpty(s))
				return s;

			if (e == null)
				e = Encoding.UTF8;
			var bytes = e.GetBytes(s);
			bytes = UrlEncodeBytesToBytesInternalNonAscii(bytes, 0, bytes.Length, false);
			return Encoding.ASCII.GetString(bytes);
		}
		/// <summary>
		/// 将传入的字符串中的空格进行编码
		/// </summary>
		/// <param name="s">要编码的字节数组。</param>
		/// <returns>一个已编码的字节数组。</returns>
		public static string UrlEncodeSpaces(string s)
		{
			if ((s != null) && (s.IndexOf(' ') >= 0))
				s = s.Replace(" ", "%20");
			return s;
		}
		/// <summary>
		/// 将字节数组转换为 URL 编码的字节数组。
		/// </summary>
		/// <param name="s">要编码的字节数组。</param>
		/// <returns>一个已编码的字节数组。</returns>
		public static byte[] UrlEncodeToBytes(string s)
		{
			if (s == null)
				return null;

			return UrlEncodeToBytes(s, Encoding.UTF8);
		}
		/// <summary>
		/// 将字符串转换为 URL 编码的字节数组。
		/// </summary>
		/// <param name="bytes">要编码的字符串。</param>
		/// <returns>一个已编码的字节数组。</returns>
		public static byte[] UrlEncodeToBytes(byte[] bytes)
		{
			if (bytes == null)
				return null;

			return UrlEncodeToBytes(bytes, 0, bytes.Length);
		}
		/// <summary>
		/// 使用指定的编码对象将字符串转换为 URL 编码的字节数组。
		/// </summary>
		/// <param name="s">要编码的字符串</param>
		/// <param name="e">指定编码方案的 System.Text.Encoding。</param>
		/// <returns>一个已编码的字节数组。</returns>
		public static byte[] UrlEncodeToBytes(string s, Encoding e)
		{
			if (s == null)
				return null;

			var bytes = e.GetBytes(s);
			return UrlEncodeBytesToBytesInternal(bytes, 0, bytes.Length, false);
		}
		/// <summary>
		/// 从数组中的指定位置开始一直到指定的字节数为止，将字节数组转换为 URL 编码的字节数组。
		/// </summary>
		/// <param name="bytes">要编码的字节数组。</param>
		/// <param name="offset">字节数组中开始编码的位置。</param>
		/// <param name="count">要编码的字节数。</param>
		/// <returns>一个已编码的字节数组。</returns>
		public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
		{
			if ((bytes == null) && (count == 0))
				return null;

			if (bytes == null)
				throw new ArgumentNullException("bytes");

			if ((offset < 0) || (offset > bytes.Length))
				throw new ArgumentOutOfRangeException("offset");

			if ((count < 0) || ((offset + count) > bytes.Length))
				throw new ArgumentOutOfRangeException("count");

			return UrlEncodeBytesToBytesInternal(bytes, offset, count, true);
		}
		/// <summary>
		/// 将字符串转换为 Unicode 字符串。
		/// </summary>
		/// <param name="s">要转换的字符串。</param>
		/// <returns>以 %UnicodeValue 表示法表示的 Unicode 字符串。</returns>
		public static string UrlEncodeUnicode(string s)
		{
			if (s == null)
				return null;

			return UrlEncodeUnicodeStringToStringInternal(s, false);
		}
		/// <summary/>
		private static string UrlEncodeUnicodeStringToStringInternal(string s, bool ignoreAscii)
		{
			var l = s.Length;
			var sb = new StringBuilder(l);
			for (var i = 0; i < l; i++)
			{
				var ch = s[i];
				if ((ch & 0xff80) == 0)
				{
					if (ignoreAscii || IsSafe(ch))
					{
						sb.Append(ch);
					}
					else if (ch == ' ')
					{
						sb.Append('+');
					}
					else
					{
						sb.Append('%');
						sb.Append(IntToHex((ch >> 4) & '\x000f'));
						sb.Append(IntToHex(ch & '\x000f'));
					}
				}
				else
				{
					sb.Append("%u");
					sb.Append(IntToHex((ch >> 12) & '\x000f'));
					sb.Append(IntToHex((ch >> 8) & '\x000f'));
					sb.Append(IntToHex((ch >> 4) & '\x000f'));
					sb.Append(IntToHex(ch & '\x000f'));
				}
			}
			return sb.ToString();
		}
		/// <summary>
		///  将 Unicode 字符串转换为字节数组。
		/// </summary>
		/// <param name="s">要转换的字符串。</param>
		/// <returns>字节数组。</returns>
		public static byte[] UrlEncodeUnicodeToBytes(string s)
		{
			if (s == null)
				return null;

			return Encoding.ASCII.GetBytes(UrlEncodeUnicode(s));
		}
		/// <summary>
		/// 对 URL 字符串的路径部分进行编码，以进行从 Web 服务器到客户端的可靠的 HTTP 传输。
		/// </summary>
		/// <param name="str">要进行 URL 编码的文本。</param>
		/// <returns>URL 编码的文本。</returns>
		public static string UrlPathEncode(string str)
		{
			if (str == null)
				return null;

			var index = str.IndexOf('?');
			if (index >= 0)
				return (UrlPathEncode(str.Substring(0, index)) + str.Substring(index));

			return UrlEncodeSpaces(UrlEncodeNonAscii(str, Encoding.UTF8));
		}
	}
}
